package handlers

import (
	"log"
	"net"
	"ota-backend/config"
	"ota-backend/models"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
)

// BruteForceProtection 防爆破保护服务
type BruteForceProtection struct{}

// NewBruteForceProtection 创建防爆破保护服务
func NewBruteForceProtection() *BruteForceProtection {
	return &BruteForceProtection{}
}

// GetClientIP 获取客户端真实IP地址
func (bf *BruteForceProtection) GetClientIP(c *gin.Context) string {
	// 尝试从各种头部获取真实IP
	ip := c.GetHeader("X-Forwarded-For")
	if ip != "" {
		// X-Forwarded-For可能包含多个IP，取第一个
		ips := strings.Split(ip, ",")
		if len(ips) > 0 {
			return strings.TrimSpace(ips[0])
		}
	}

	ip = c.GetHeader("X-Real-IP")
	if ip != "" {
		return ip
	}

	ip = c.GetHeader("X-Forwarded")
	if ip != "" {
		return ip
	}

	ip = c.GetHeader("X-Cluster-Client-IP")
	if ip != "" {
		return ip
	}

	// 最后使用RemoteAddr
	ip = c.ClientIP()
	if net.ParseIP(ip) != nil {
		return ip
	}

	return ""
}

// IsIPBlocked 检查IP是否被封禁
func (bf *BruteForceProtection) IsIPBlocked(ip string) bool {
	if !config.GetBruteForceProtectionEnabled() {
		return false
	}

	var blacklist models.IPBlacklist
	db := config.DB

	// 查找该IP的封禁记录
	err := db.Where("ip = ? AND (unblocked_at IS NULL OR unblocked_at > ?)",
		ip, time.Now()).First(&blacklist).Error

	if err != nil {
		// 没有找到封禁记录
		return false
	}

	// 检查是否已过期
	if blacklist.UnblockedAt != nil && blacklist.UnblockedAt.Before(time.Now()) {
		// 封禁已过期，清理记录
		db.Delete(&blacklist)
		return false
	}

	log.Printf("IP %s 被封禁，原因: %s", ip, blacklist.Reason)
	return true
}

// RecordLoginFailure 记录登录失败尝试
func (bf *BruteForceProtection) RecordLoginFailure(c *gin.Context, username string) {
	if !config.GetBruteForceProtectionEnabled() {
		return
	}

	ip := bf.GetClientIP(c)
	if ip == "" {
		return
	}

	userAgent := c.GetHeader("User-Agent")

	// 记录失败尝试
	failure := models.LoginFailure{
		IP:        ip,
		Username:  username,
		Timestamp: time.Now(),
		UserAgent: userAgent,
	}

	db := config.DB
	if err := db.Create(&failure).Error; err != nil {
		log.Printf("记录登录失败失败: %v", err)
		return
	}

	log.Printf("记录登录失败: IP=%s, Username=%s", ip, username)

	// 检查是否需要封禁IP
	bf.CheckAndBlockIP(ip)
}

// CheckAndBlockIP 检查并封禁IP
func (bf *BruteForceProtection) CheckAndBlockIP(ip string) {
	if !config.GetBruteForceProtectionEnabled() {
		return
	}

	db := config.DB
	maxAttempts := config.GetMaxLoginAttempts()
	windowMinutes := config.GetLoginWindowMinutes()
	blockDurationMinutes := config.GetBlockDurationMinutes()

	// 计算时间窗口
	windowStart := time.Now().Add(-time.Duration(windowMinutes) * time.Minute)

	// 统计时间窗口内的失败次数
	var failureCount int64
	err := db.Model(&models.LoginFailure{}).Where("ip = ? AND timestamp > ?",
		ip, windowStart).Count(&failureCount).Error

	if err != nil {
		log.Printf("统计登录失败次数失败: %v", err)
		return
	}

	log.Printf("IP %s 在 %d 分钟内失败次数: %d", ip, windowMinutes, failureCount)

	// 如果超过最大尝试次数，封禁IP
	if failureCount >= int64(maxAttempts) {
		// 检查是否已经被封禁
		var existingBlock models.IPBlacklist
		err := db.Where("ip = ? AND (unblocked_at IS NULL OR unblocked_at > ?)",
			ip, time.Now()).First(&existingBlock).Error

		if err == nil {
			// 已经被封禁，更新失败次数
			existingBlock.FailureCount = int(failureCount)
			db.Save(&existingBlock)
			return
		}

		// 创建新的封禁记录
		unblockTime := time.Now().Add(time.Duration(blockDurationMinutes) * time.Minute)
		blacklist := models.IPBlacklist{
			IP:           ip,
			BlockedAt:    time.Now(),
			UnblockedAt:  &unblockTime,
			Reason:       "多次登录失败，触发防爆破保护",
			FailureCount: int(failureCount),
		}

		if err := db.Create(&blacklist).Error; err != nil {
			log.Printf("封禁IP失败: %v", err)
			return
		}

		log.Printf("IP %s 已被封禁 %d 分钟，失败次数: %d", ip, blockDurationMinutes, failureCount)
	}
}

// CleanupOldRecords 清理旧记录
func (bf *BruteForceProtection) CleanupOldRecords() {
	if !config.GetBruteForceProtectionEnabled() {
		return
	}

	db := config.DB
	cleanupHours := config.GetCleanupHours()
	cutoffTime := time.Now().Add(-time.Duration(cleanupHours) * time.Hour)

	// 清理旧的登录失败记录
	result := db.Where("timestamp < ?", cutoffTime).Delete(&models.LoginFailure{})
	if result.Error != nil {
		log.Printf("清理旧登录失败记录失败: %v", result.Error)
	} else if result.RowsAffected > 0 {
		log.Printf("清理了 %d 条旧登录失败记录", result.RowsAffected)
	}

	// 清理已过期的IP封禁记录
	result = db.Where("unblocked_at IS NOT NULL AND unblocked_at < ?", time.Now()).Delete(&models.IPBlacklist{})
	if result.Error != nil {
		log.Printf("清理过期IP封禁记录失败: %v", result.Error)
	} else if result.RowsAffected > 0 {
		log.Printf("清理了 %d 条过期IP封禁记录", result.RowsAffected)
	}
}

// StartCleanupRoutine 启动定期清理例程
func (bf *BruteForceProtection) StartCleanupRoutine() {
	if !config.GetBruteForceProtectionEnabled() {
		return
	}

	go func() {
		ticker := time.NewTicker(1 * time.Hour) // 每小时执行一次清理
		defer ticker.Stop()

		for {
			select {
			case <-ticker.C:
				bf.CleanupOldRecords()
			}
		}
	}()

	log.Println("防爆破保护清理例程已启动")
}

// GetBlockedIPs 获取被封禁的IP列表
func (bf *BruteForceProtection) GetBlockedIPs(c *gin.Context) {
	db := config.DB
	var blacklist []models.IPBlacklist

	// 只获取当前有效的封禁记录
	err := db.Where("unblocked_at IS NULL OR unblocked_at > ?", time.Now()).
		Order("blocked_at DESC").Find(&blacklist).Error

	if err != nil {
		c.JSON(500, gin.H{"error": "获取封禁IP列表失败"})
		return
	}

	c.JSON(200, gin.H{
		"data":  blacklist,
		"total": len(blacklist),
	})
}

// UnblockIP 解封IP地址
func (bf *BruteForceProtection) UnblockIP(c *gin.Context) {
	ip := c.Param("ip")
	if ip == "" {
		c.JSON(400, gin.H{"error": "IP地址不能为空"})
		return
	}

	db := config.DB

	// 更新封禁记录，设置解封时间为当前时间
	now := time.Now()
	result := db.Model(&models.IPBlacklist{}).
		Where("ip = ? AND (unblocked_at IS NULL OR unblocked_at > ?)", ip, now).
		Update("unblocked_at", now)

	if result.Error != nil {
		c.JSON(500, gin.H{"error": "解封IP失败"})
		return
	}

	if result.RowsAffected == 0 {
		c.JSON(404, gin.H{"error": "未找到该IP的封禁记录"})
		return
	}

	log.Printf("管理员手动解封IP: %s", ip)
	c.JSON(200, gin.H{"message": "IP解封成功"})
}

// GetLoginFailures 获取登录失败记录
func (bf *BruteForceProtection) GetLoginFailures(c *gin.Context) {
	db := config.DB
	var failures []models.LoginFailure

	// 支持分页
	page := c.DefaultQuery("page", "1")
	pageSize := c.DefaultQuery("page_size", "50")
	ip := c.Query("ip") // 可选的IP过滤

	query := db.Model(&models.LoginFailure{})

	if ip != "" {
		query = query.Where("ip = ?", ip)
	}

	// 计算总数
	var total int64
	query.Count(&total)

	// 分页查询 - 解析参数
	pageInt := 1
	pageSizeInt := 50

	if p := page; p != "" {
		if pi := int(p[0] - '0'); pi > 0 && pi < 10 {
			pageInt = pi
		}
	}
	if ps := pageSize; ps != "" && len(ps) > 0 {
		if psi := int(ps[0] - '0'); psi > 0 && psi < 10 {
			pageSizeInt = psi * 10 // 简单处理，支持10,20,30等
		}
	}

	offset := (pageInt - 1) * pageSizeInt

	err := query.Order("timestamp DESC").
		Limit(pageSizeInt).Offset(offset).
		Find(&failures).Error

	if err != nil {
		c.JSON(500, gin.H{"error": "获取登录失败记录失败"})
		return
	}

	c.JSON(200, gin.H{
		"data":      failures,
		"total":     total,
		"page":      pageInt,
		"page_size": pageSizeInt,
	})
}

// ClearLoginFailures 清理登录失败记录
func (bf *BruteForceProtection) ClearLoginFailures(c *gin.Context) {
	db := config.DB
	ip := c.Query("ip") // 可选的IP过滤

	query := db.Model(&models.LoginFailure{})

	if ip != "" {
		query = query.Where("ip = ?", ip)
	}

	result := query.Delete(&models.LoginFailure{})

	if result.Error != nil {
		c.JSON(500, gin.H{"error": "清理登录失败记录失败"})
		return
	}

	log.Printf("管理员清理了 %d 条登录失败记录 (IP: %s)", result.RowsAffected, ip)
	c.JSON(200, gin.H{
		"message":       "清理成功",
		"deleted_count": result.RowsAffected,
	})
}
